<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;

/**
 * 文章内容隐藏插件
 * 通过 [secret] 和 [/secret] 标签隐藏部分内容，支持指定隐藏条件并显示不同提示
 * 
 * [secret type="login"]
 * 只有登录用户才能查看的内容
 * 例如：会员专享信息、个人化内容
 * [/secret]
 * 
 * [secret type="comment"]
 * 只有对本文发表过评论的用户才能查看的内容
 * 例如：资源下载链接、详细教程
 * [/secret]
 * 
 * [secret type="always"]
 * 这段内容仅管理员可见
 * 例如：内部备注、待修改内容
 * [/secret]
 * 
 * 
 * 
 * @package SecretContent
 * @author 蔥籽
 * @version 1.2.0
 * @link https://chencong.blog
 */
class SecretContent_Plugin implements Typecho_Plugin_Interface
{
    /**
     * 激活插件方法,如果激活失败,直接抛出异常
     * 
     * @access public
     * @return void
     * @throws Typecho_Plugin_Exception
     */
    public static function activate()
    {
        // 注册内容处理钩子
        Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = array('SecretContent_Plugin', 'parseContent');
        Typecho_Plugin::factory('Widget_Abstract_Contents')->excerptEx = array('SecretContent_Plugin', 'parseExcerpt');
        
        return _t('请配置插件设置以启用内容隐藏功能');
    }
    
    /**
     * 禁用插件方法,如果禁用失败,直接抛出异常
     * 
     * @static
     * @access public
     * @return void
     * @throws Typecho_Plugin_Exception
     */
    public static function deactivate() {}
    
    /**
     * 获取插件配置面板
     * 
     * @access public
     * @param Typecho_Widget_Helper_Form $form 配置表单
     * @return void
     */
    public static function config(Typecho_Widget_Helper_Form $form)
    {
        // 默认隐藏条件设置（当标签中未指定时使用）
        $defaultCondition = new Typecho_Widget_Helper_Form_Element_Radio(
            'defaultCondition',
            array(
                'login' => _t('登录用户可见'),
                'comment' => _t('评论后可见'),
                'always' => _t('始终隐藏(仅管理员可见)')
            ),
            'login',
            _t('默认隐藏条件'),
            _t('当secret标签中未指定条件时使用的默认设置')
        );
        $form->addInput($defaultCondition);
        
        // 登录可见的提示信息
        $loginMessage = new Typecho_Widget_Helper_Form_Element_Textarea(
            'loginMessage',
            null,
            '注意：此内容需要登录后才能查看，请先登录您的账号。',
            _t('登录可见提示信息'),
            _t('当内容设置为"登录用户可见"且用户未登录时显示的提示文本')
        );
        $form->addInput($loginMessage);
        
        // 评论可见的提示信息
        $commentMessage = new Typecho_Widget_Helper_Form_Element_Textarea(
            'commentMessage',
            null,
            '注意：此内容需要评论后才能查看，请先发表您的评论。',
            _t('评论可见提示信息'),
            _t('当内容设置为"评论后可见"且用户未评论时显示的提示文本')
        );
        $form->addInput($commentMessage);
        
        // 始终隐藏的提示信息
        $alwaysMessage = new Typecho_Widget_Helper_Form_Element_Textarea(
            'alwaysMessage',
            null,
            '注意：此内容仅对管理员可见，抱歉无法为您展示。',
            _t('始终隐藏提示信息'),
            _t('当内容设置为"始终隐藏"时显示的提示文本')
        );
        $form->addInput($alwaysMessage);
        
        // 管理员是否始终可见
        $adminSee = new Typecho_Widget_Helper_Form_Element_Checkbox(
            'adminSee',
            array('1' => _t('管理员始终可见隐藏内容')),
            array('1'),
            _t('管理员权限')
        );
        $form->addInput($adminSee);
    }
    
    /**
     * 个人用户的配置面板
     * 
     * @access public
     * @param Typecho_Widget_Helper_Form $form
     * @return void
     */
    public static function personalConfig(Typecho_Widget_Helper_Form $form) {}
    
    /**
     * 解析内容，替换秘密标签
     * 
     * @access public
     * @param string $content 文章内容
     * @param Widget_Abstract_Contents $widget 内容对象
     * @return string
     */
    public static function parseContent($content, $widget)
    {
        return self::parse($content, $widget, false);
    }
    
    /**
     * 解析摘要，替换秘密标签
     * 
     * @access public
     * @param string $excerpt 文章摘要
     * @param Widget_Abstract_Contents $widget 内容对象
     * @return string
     */
    public static function parseExcerpt($excerpt, $widget)
    {
        return self::parse($excerpt, $widget, true);
    }
    
    /**
     * 核心解析方法
     * 
     * @access private
     * @param string $text 需要解析的文本
     * @param Widget_Abstract_Contents $widget 内容对象
     * @param bool $isExcerpt 是否为摘要
     * @return string
     */
    private static function parse($text, $widget, $isExcerpt)
    {
        // 如果是摘要，直接移除所有秘密内容
        if ($isExcerpt) {
            return preg_replace('/\[secret(.*?)\](.*?)\[\/secret\]/sm', '', $text);
        }
        
        // 获取插件配置
        $options = Typecho_Widget::widget('Widget_Options')->plugin('SecretContent');
        
        // 使用正则表达式匹配所有secret标签，包括带有type属性的
        return preg_replace_callback(
            '/\[secret(.*?)\](.*?)\[\/secret\]/sm',
            function($matches) use ($widget, $options) {
                // 提取type属性值
                $type = '';
                if (preg_match('/type\s*=\s*["\'](login|comment|always)["\']/', $matches[1], $typeMatch)) {
                    $type = $typeMatch[1];
                }
                
                // 如果没有指定type，使用默认设置
                if (empty($type)) {
                    $type = $options->defaultCondition;
                }
                
                // 检查是否有权限查看隐藏内容
                $canSee = self::canSeeSecretContent($widget, $options, $type);
                
                if ($canSee) {
                    // 有权限，显示内容
                    return $matches[2];
                } else {
                    // 无权限，根据不同类型显示对应提示信息
                    switch ($type) {
                        case 'login':
                            $message = !empty($options->loginMessage) ? $options->loginMessage : '此内容需要登录后才能查看，请先登录您的账号。';
                            break;
                        case 'comment':
                            $message = !empty($options->commentMessage) ? $options->commentMessage : '此内容需要评论后才能查看，请先发表您的评论。';
                            break;
                        case 'always':
                            $message = !empty($options->alwaysMessage) ? $options->alwaysMessage : '此内容仅对管理员可见，抱歉无法为您展示。';
                            break;
                        default:
                            $message = '此内容受到保护，无法查看。';
                    }
                    
                    return '<div class="secret-content-hidden secret-type-' . $type . '" style="color: #d32f2f; font-weight: bold; padding: 10px; border: 1px solid #ffcccc; background-color: #fff5f5; border-radius: 4px; margin: 10px 0;">' . $message . '</div>';
                }
            },
            $text
        );
    }
    
    /**
     * 检查是否有权限查看隐藏内容
     * 
     * @access private
     * @param Widget_Abstract_Contents $widget 内容对象
     * @param Typecho_Config $options 插件配置
     * @param string $type 隐藏条件类型
     * @return bool
     */
    private static function canSeeSecretContent($widget, $options, $type)
    {
        $user = Typecho_Widget::widget('Widget_User');
        
        // 管理员始终可见
        if ($user->hasLogin() && $user->group == 'administrator' && in_array('1', $options->adminSee)) {
            return true;
        }
        
        // 根据不同条件判断
        switch ($type) {
            case 'login':
                // 登录用户可见
                return $user->hasLogin();
                break;
                
            case 'comment':
                // 评论后可见
                if ($user->hasLogin()) {
                    // 检查当前用户是否评论过该文章
                    $cid = $widget->cid;
                    $db = Typecho_Db::get();
                    $prefix = $db->getPrefix();
                    
                    $count = $db->fetchObject($db->select('COUNT(cid) AS num')
                        ->from($prefix . 'comments')
                        ->where('cid = ?', $cid)
                        ->where('authorId = ?', $user->uid))->num;
                        
                    return $count > 0;
                }
                return false;
                break;
                
            case 'always':
                // 始终隐藏(仅管理员可见，已在前面判断)
                return false;
                break;
                
            default:
                return false;
        }
    }
}
?>
